package com.tianji.promotion.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.entity.Coupon;
import com.tianji.promotion.entity.CouponScope;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author xianggu
 * @since 2023-06-03
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    private final ICouponScopeService scopeService;
    private final IExchangeCodeService codeService;
    /**
     * 新增优惠券接口
     *
     * @param dto
     */
    @Transactional
    @Override
    public void saveCoupon(CouponFormDTO dto) {
        //1.准备数据po
        Coupon po = BeanUtils.copyBean(dto, Coupon.class);
        //2.新增数据
        this.save(po);
        if (!dto.getSpecific()) {
            return;
        }
        //3.保存优惠券范围信息
        List<Long> scopes = dto.getScopes();
        Long id = po.getId();
        List<CouponScope> list = scopes.stream().map(s -> new CouponScope().setCouponId(id).setBizId(s)).collect(Collectors.toList());
        scopeService.saveBatch(list);
    }

    /**
     * 分页查询优惠券接口
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<CouponPageVO> queryCouponByPage(CouponQuery query) {
        String name = query.getName();
        Integer status = query.getStatus();
        Integer type = query.getType();
        //1.分页查询
        Page<Coupon> page = this.lambdaQuery()
                .eq(status != null, Coupon::getStatus, status)
                .eq(type != null, Coupon::getType, type)
                .like(StringUtils.isNotBlank(name), Coupon::getName, name)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        //2.组装vo
        List<Coupon> list = page.getRecords();
        List<CouponPageVO> vos = BeanUtils.copyList(list, CouponPageVO.class);
        //3.返回
        return PageDTO.of(page,vos);
    }

    /**
     * 发放优惠券接口
     *
     * @param dto
     */
    @Override
    public void beginIssue(CouponIssueFormDTO dto) {
        //1.查询优惠券
        Long id = dto.getId();
        Coupon coupon = this.getById(id);
        if (coupon == null) {
            return;
        }
        Integer totalNum = coupon.getTotalNum();
        //2.判断优惠券是否进行中状态
        if(coupon.getStatus() == CouponStatus.ISSUING){
            throw new BadRequestException("优惠券状态进行中，你省省吧！");
        }
        //3.发放时间是否小于当前时间 ？进行中：未开始
        LocalDateTime issueBeginTime = dto.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();
        Coupon po = BeanUtils.copyBean(dto, Coupon.class);
        if (issueBeginTime == null || !issueBeginTime.isAfter(now)) {
            //进行中
            po.setStatus(CouponStatus.ISSUING);
            po.setIssueBeginTime(now);
        }else{
            //未开始
            po.setStatus(CouponStatus.UN_ISSUE);
        }
        //4.修改请求
        this.updateById(po);
        //5.兑换码生成
        if(coupon.getObtainWay() == ObtainType.ISSUE && coupon.getStatus() == CouponStatus.DRAFT) {
            coupon.setIssueEndTime(po.getIssueEndTime());
            codeService.autoEchangeCode(coupon);
        }
    }

    /**
     * 修改优惠券接口
     *
     * @param dto
     */
    @Override
    public void updateCoupon(CouponFormDTO dto) {
        //1.根据id查询优惠券状态
        Long id = dto.getId();
        Coupon coupon = this.getById(id);
        if (coupon == null) {
            return;
        }
        //2.判断优惠券是否待发放状态
        if(!(coupon.getStatus() == CouponStatus.DRAFT)){
            throw new BadRequestException("只有待发放状态的优惠券可以修改，你省省吧！");
        }
        //3.修改优惠券
        Coupon po = BeanUtils.copyBean(dto, Coupon.class);
        this.updateById(po);
    }

    /**
     * 删除优惠券接口
     *
     * @param id
     */
    @Override
    public void deleteCoupon(Long id) {
        //1.根据id查询优惠券状态
        Coupon coupon = this.getById(id);
        if (coupon == null) {
            return;
        }
        //2.判断优惠券是否待发放状态
        if(!(coupon.getStatus() == CouponStatus.DRAFT)){
            throw new BadRequestException("只有待发放状态的优惠券可以删除，你省省吧！");
        }
        //3.删除优惠券
        this.removeById(id);
    }

    /**
     * 分页查询优惠券接口
     *
     * @param id
     * @return
     */
    @Override
    public CouponPageVO getByIdCoupon(Long id) {
        //1.根据id查询优惠券状态
        Coupon coupon = this.getById(id);
        if (coupon == null) {
            return new CouponPageVO();
        }

        //组装vo
        CouponPageVO vo = BeanUtils.copyBean(coupon, CouponPageVO.class);
        return vo;
    }

    /**
     * 暂停优惠券
     *
     * @param id
     */
    @Override
    public void stopCoupon(Long id) {
        //1.根据id查询优惠券状态
        Coupon coupon = this.getById(id);
        if (coupon == null) {
            return;
        }
        //2.判断优惠券是否待发放状态
        if(!(coupon.getStatus() == CouponStatus.ISSUING)){
            throw new BadRequestException("只有进行中状态的优惠券可以暂停，你省省吧！");
        }
        this.lambdaUpdate()
                .set(Coupon::getStatus,CouponStatus.ISSUING)
                .eq(Coupon::getId,id)
                .update();
    }
}
